package com.zmn.oms.business.interfaces.perf;

import com.zmn.common.utils.pager.Pages;
import com.zmn.oms.common.constant.MeasureTypeEnum;
import com.zmn.oms.model.entity.perf.PerfDimension;
import com.zmn.oms.model.entity.perf.PerfFact;
import com.zmn.oms.model.entity.perf.PerfTimeQuery;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 绩效查询服务
 *
 * @param <D>纬度对象
 * @param <V>视图对象
 * @author hankangshuai
 * @since 2019/11/20
 **/
public interface PerfQueryBService<V, D extends PerfDimension, Q extends Pages & PerfTimeQuery> {
    /**
     * 根据条件分页查询纬度
     *
     * @param query 查询条件
     * @return 纬度列表
     */
    List<D> listDimensionPageByQuery(Q query);

    /**
     * 根据条件查询纬度ID
     *
     * @param query 查询条件
     * @return 纬度ID集合
     */
    List<Integer> listDimensionIdByQuery(Q query);

    /**
     * 根据纬度查询事实
     *
     * @param dimensionId 纬度ID集合
     * @return 事实实体
     */
    List<PerfFact> listFactByDimensionId(List<Integer> dimensionId, PerfTimeQuery perfTimeQuery);

    /**
     * 将纬度和事实合并成VO
     *
     * @param d          单个纬度
     * @param singleFact 单条事实
     * @return VO
     */
    V mergeToVO(Optional<D> d, Map<MeasureTypeEnum, Long> singleFact);

    /**
     * 根据条件查询
     *
     * @param query 查询对象
     * @return VO集合
     */
    default List<V> listByQuery(Q query) {
        query.setPageIndex(1);
        query.setPageSize(10000);
        return this.listPageByQuery(query);
    }

    /**
     * 分页查询
     *
     * @param query 查询
     * @return VO集合
     */
    default List<V> listPageByQuery(Q query) {
        List<D> dimensionByQuery = listDimensionPageByQuery(query);
        List<Integer> dimensionIdList = dimensionByQuery.stream().map(PerfDimension::getDimensionId).collect(Collectors.toList());
        List<PerfFact> perfFacts = listFactByDimensionId(dimensionIdList, query);
        return mergeToVO(dimensionByQuery, perfFacts);
    }

    /**
     * 批量将纬度和事实合并成VO
     *
     * @param dimensionList 纬度集合
     * @param factList      事实集合
     * @return VO集合
     */
    default List<V> mergeToVO(List<D> dimensionList, List<PerfFact> factList) {
        Map<Integer, Map<MeasureTypeEnum, Long>> factMap = factList.stream().collect(Collectors.groupingBy(PerfFact::getDimensionId,
                Collectors.toMap(PerfFact::getMeasureType,
                        PerfFact::getMeasureValue,
                        Long::sum,
                        () -> new EnumMap<>(MeasureTypeEnum.class))
        ));
        return dimensionList.stream().map(d -> {
            Map<MeasureTypeEnum, Long> singleFact = factMap.getOrDefault(d.getDimensionId(), Collections.emptyMap());
            return mergeToVO(Optional.of(d), singleFact);
        }).collect(Collectors.toList());
    }

    /**
     * 条件查询(最多10000条)
     *
     * @param query 查询条件
     * @return 实体列表
     */
    default List<D> listDimensionByQuery(Q query) {
        query.setPageIndex(1);
        query.setPageSize(10000);
        return listDimensionPageByQuery(query);
    }

    /**
     * 根据条件获取汇总
     *
     * @param query 查询条件
     * @return 汇总实体
     */
    default V getTotalLine(Q query) {
        List<Integer> dimensionIdByQuery = listDimensionIdByQuery(query);
        if (CollectionUtils.isEmpty(dimensionIdByQuery)) {
            return mergeToVO(Optional.empty(), Collections.emptyMap());
        }
        List<PerfFact> perfFacts = listFactByDimensionId(dimensionIdByQuery, query);
        Map<MeasureTypeEnum, Long> collect = perfFacts.stream().collect(Collectors.toMap(PerfFact::getMeasureType, PerfFact::getMeasureValue, Long::sum));
        return mergeToVO(Optional.empty(), collect);
    }
}
